package core

import (
	"log"
	"fmt"
)

//定义区块链
type Blockchain struct {
	Blocks []*Block //区块数组
}

//生成新的区块链
func NewBlockchain() *Blockchain {
	//创建创世区块，将其追加到区块链的第一个区块中
	genesisBlock := GenerateGenesisBlock()
	blockchain := Blockchain{}
	blockchain.ApendBlock(&genesisBlock)
	log.Println("完成：【创建创世区块，将其追加到区块链的第一个区块中】")
	return &blockchain

}

//将新的数据创建新的区块链，并追加到当前的区块链中
func (bc *Blockchain) SendData(data string) {
	//从当前区块链中，获取到最后一个区块，作为父区块
	preBlock := bc.Blocks[len(bc.Blocks)-1]
	//生成新区块
	newBlock := GenerateNewBlock(*preBlock, data);
	//添加到当前区块链中
	bc.ApendBlock(&newBlock)
	log.Println("完成：【新的数据添加的区块链】")
}

//添加区块，将新的区块添加到区块链中
func (bc *Blockchain) ApendBlock(newBlock *Block) {
	//如果当前区块链中还没有区块（创世区块），则直接追加
	if len(bc.Blocks) == 0 {
		bc.Blocks = append(bc.Blocks, newBlock)
		return
	}
	//对新追加的区块数据进行校验
	if (isValid(*newBlock, *bc.Blocks[len(bc.Blocks)-1])) {
		//验证通过，进行追加
		bc.Blocks = append(bc.Blocks, newBlock)
	} else {
		//打印非法区块
		log.Fatal("invalid block")
	}
}

//打印当前区块链中的区块详细信息
func (bc *Blockchain) Print() {
	for _, block := range bc.Blocks {
		fmt.Printf("Index: %d\n", block.Index)
		fmt.Printf("Prev.Hash: %s\n", block.PrevBlockHash)
		fmt.Printf("Curr.Hash: %s\n", block.Hash)
		fmt.Printf("Data: %s\n", block.Data)
		fmt.Printf("Timestamp:%d\n", block.Timestamp)
		fmt.Println()
	}

}

//数据校验，传入新区块及其父区块
func isValid(newBlock Block, oldBlock Block) bool {

	if newBlock.Index-1 != oldBlock.Index {
		return false
	}

	if newBlock.PrevBlockHash != oldBlock.Hash {
		return false
	}

	if calculateHash(newBlock) != newBlock.Hash {
		return false
	}

	return true
}
